<?php

namespace Cloud;

use Cloud\Support\Algorithm;
use Redis;
use Swoole\Coroutine\Http\Client;
use Swoole\Server as SwoServer;

abstract class Server
{
    /**
     * Swoole Server
     *
     * @var SwoServer
     */
    protected $swoServer;

    /**
     * @var Redis
     */
    protected $redis;

    /**
     * @var Algorithm
     */
    protected $algorithm;

    /**
     * 待监听的接口
     *
     * @var string
     */
    protected $host = '0.0.0.0';

    /**
     * 监听的端口
     *
     * @var int
     */
    protected $port = 9501;

    /**
     * redis key
     *
     * @var string
     */
    public $serverKey = 'im-server';

    /**
     * 主进程 ID
     * 管理进程 ID
     * worker 进程 ID 集合
     * task 进程 ID 结合
     *
     * @var array
     */
    protected $pidMap = [
        'master_pid' => 0,
        'manager_pid' => 0,
        'worker_pid' => [],
        'task_pid' => [],
    ];

    /**
     * Swoole 事件集合
     *
     * @var array
     */
    protected $event = [
        // 这是所有服务均会注册的事件
        "server" => [
            // 事件   =》 事件函数
            "start"        => "onStart",
            "managerStart" => "onManagerStart",
            "managerStop"  => "onManagerStop",
            "shutdown"     => "onShutdown",
            "workerStart"  => "onWorkerStart",
            "workerStop"   => "onWorkerStop",
            "workerError"  => "onWorkerError",
        ],
        // 子类的服务
        "sub" => [

        ],
        // 额外扩展的回调函数
        // 如 onTask等
        "ext" => [

        ]
    ];

    /**
     * Swoole 配置信息
     *
     * @var array
     */
    protected $config = [
        'task_worker_num' => 0
    ];

    /**
     * 是否开启热加载
     *
     * @var bool
     */
    protected $watchFile = true;

    protected $runtimePath = 'runtime/pid';

    public function __construct()
    {

    }

    /**
     * Note: 初始化事件
     *
     * @return mixed
     * @author: Zhao Zhiqiang
     * @since: 2021/5/11 17:29
     */
    abstract protected function initEvent();

    /**
     * Note: 创建服务器
     *
     * @return mixed
     * @author: Zhao Zhiqiang
     * @since: 2021/5/11 17:29
     */
    abstract protected function createServer();

    /**
     * Note: 设置 Swoole 事件
     *
     * @author: Zhao Zhiqiang
     * @since: 2021/5/11 17:30
     */
    protected function setSwoEvent()
    {
        foreach ($this->event as $type => $events) {
            foreach ($events as $event => $func) {
                $this->swoServer->on($event, [$this, $func]);
            }
        }
    }

    /**
     * Note: 注册事件
     *
     * @param string $type
     * @param array $event
     * @return $this
     * @author: Zhao Zhiqiang
     * @since: 2021/5/11 17:24
     */
    protected function setEvent(string $type, array $event)
    {
        if ($type !== 'server') {
            $this->event[$type] = $event;
        }

        return $this;
    }

    /**
     * Note: 启动 Swoole 服务
     *
     * @author: Zhao Zhiqiang
     * @since: 2021/5/11 17:34
     */
    public function start()
    {
        $this->createServer();

        $this->swoServer->set($this->config);

        // 设置注册函数
        $this->initEvent();

        // 设置 swoole 回调函数
        $this->setSwoEvent();

        $this->swoServer->start();
    }

    public function onStart(SwoServer $server)
    {
        $this->pidMap['master_pid'] = $server->master_pid;
        $this->pidMap['manager_pid'] = $server->manager_pid;
    }

    public function onManagerStart(SwoServer $server)
    {

    }

    public function onManagerStop(SwoServer $server)
    {

    }

    public function onShutdown(SwoServer $server)
    {

    }

    public function onWorkerStart(SwoServer $server, int $worker_id)
    {
        $this->redis = new Redis();
        $this->redis->pconnect('redis', 6379);

        $this->algorithm = new Algorithm();
    }

    public function onWorkerStop(SwoServer $server, int $worker_id)
    {

    }

    public function onWorkerError(SwoServer $server, int $workerId, int $workerPid, int $exitCode, int $signal)
    {

    }

    public function getHost(): string
    {
        return $this->host;
    }

    public function getPort(): int
    {
        return $this->port;
    }
}
